package dbops

import (
	"database/sql"
	"log"
	"strconv"
	"sync"
	"video_server/api/defs"
)

// -------  session 操作 DB -----

// InsertSession 插入session 操作
func InsertSession(sid string, ttl int64, uname string) error {

	// 把整形转换为字符串
	ttlstr := strconv.FormatInt(ttl, 10)
	// 使用预编译SQL
	stmInsert, err := dbConn.Prepare(`insert into sessions (session_id, ttl, login_name) values (?,?,?)`)
	if err != nil {
		log.Printf(err.Error())
		return err
	}

	// 设置值
	_, err = stmInsert.Exec(sid, ttlstr, uname)
	if err != nil {
		log.Printf(err.Error())
		return err
	}

	defer stmInsert.Close()
	return nil
}

// RetrieveSession 检索会话
func RetrieveSession(sid string) (*defs.SimpleSession, error) {
	ss := &defs.SimpleSession{}

	// 使用预编译SQL
	stmQuery, err := dbConn.Prepare("select ttl, login_name from sessions where session_id = ?")
	if err != nil {
		return nil, err
	}

	var ttl string
	var loginName string

	// 设置参数，并取值
	err = stmQuery.QueryRow(sid).Scan(&ttl, &loginName)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}

	// 把有效期转换为 int64 类型的整型数据(也就是这个整型是 64 位长度)
	if res, err := strconv.ParseInt(ttl, 10, 64); err == nil {
		ss.TTL = res
		ss.Username = loginName
	} else {
		return nil, err
	}

	defer stmQuery.Close()
	return ss, nil

}

// RetrieveAllSession 因为 session 是 key-value 形式的，所以返回值是 Map， 同时有需要保证多个线程之间的线程安全问题
// RetrieveAllSession 检索所有的session
func RetrieveAllSession() (*sync.Map, error) {

	// 预编译SQL
	stmQuery, err := dbConn.Prepare("select * from sessions inner join users on sessions.login_name = users.login_name")
	if err != nil {
		return nil, err
	}

	// 查询
	rows, err := stmQuery.Query()
	if err != nil {
		return nil, err
	}

	// 并发 Map
	m := &sync.Map{}

	// 循环迭代数据
	for rows.Next() {
		var sessionID string
		var ttl string
		var loginName string
		if er := rows.Scan(&sessionID, &ttl, &loginName); er != nil {
			log.Printf("读取session失败！错误：%s", er)
			break
		}

		if ttl, err1 := strconv.ParseInt(sessionID, 10, 64); err1 == nil {
			ss := &defs.SimpleSession{Username: loginName, TTL: ttl}
			// 放入并发 Map 中
			m.Store(sessionID, ss)
			log.Printf("session id: %s, ttl: %d", sessionID, ttl)
		}

	}

	return m, nil

}

// DeleteSessionId 删除 session
func DeleteSessionID(sid string) error {

	// 预编译SQL
	stmDelete, err := dbConn.Prepare("delete from sessions where session_id = ?")
	if err != nil {
		return err
	}

	// 设置值
	_, err = stmDelete.Exec(sid)
	if err != nil {
		return err
	}

	defer stmDelete.Close()
	return nil
}
